Android crash恢复

apk崩溃情形

前台时崩溃

1、界面一创建就崩溃,可能在onCreate等方法中读取数据造成的Crash
2、界面创建且绘制完成正常显示,在用户执行某个操作,如点击按钮执行某个操作等造成的Crash
3、其它异步线程、服务等在后台执行任务时导致的Crash.

上面的情况都应恢复绘制完成后的界面,也就是栈顶Activity是在Crash之前用户所看到的界面,而之前创建且未销毁的Activity也应该进行恢复。

后台时崩溃

1
2
1、进程未挂,无非就是异步线程、server等后台任务发生异常时导致的Crash
2、进程已挂,进程被360等工具杀死了,常见的是push过来了然后唤起App进程,在解析push信息时候导致Crash

ActivityStack恢复的操作,都是先恢复栈中的Activity,无Activity时则重启应用

主页的回退

在进行恢复Activity时,如果只是恢复栈顶Activity,当用户在这个界面不进行跳转操作而是直接按返回键,这将导致直接退出程序,所以对于这个情况应该是回退到应用的主页,Recovery中有个参数mainPage,如果设置了就表示需要回退到主页,没有设置则不进行回退

这个过程中涉及到获取App内Activity栈内的数量和栈底Activity,是开发人员应该都知道获取这两个信息是通过getRunningTasks来获取,不过可惜,在5.0以后Google对权限进行了收敛,目地是保护App的信息安全,这个方法在5.0以后将失效,所以需要另外一种方法进行兼容,于是乎看6.0源码又发现Google在5.0收敛了整个权限,导致本App的都获取不到,但是在6.0又放出来了,不过只能获取本应用的数据,所以兼容的策略是5.0~6.0自己维护一个ActivityStack

连续Crash的处理

如果一分钟内进行了两次恢复后还导致Crash,则不进行恢复而是重启应用,或者重启并清空缓存,以便恢复App刚安装时的状态

项目地址

1
https://github.com/Sunzxyong/Recovery

but~ 我觉得这个项目还是有点鸡肋的,自己监听就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private static class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {

private Context mContext;

public MyUncaughtExceptionHandler(Context context) {
mContext = context;
}

@Override
public void uncaughtException(Thread thread, final Throwable ex) {
new Thread() {

@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "很抱歉,程序异常",
Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();

ThreadPoolManager.EXECUTOR.execute(new Runnable() {

@Override
public void run() {

Log.e("DebugLog", "exception:" + getExceptionTrace(ex));
ex.printStackTrace();

AlarmManager mgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(mContext, SplashActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("crash", true);
PendingIntent restartIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用

Process.killProcess(Process.myPid());
System.exit(0);
}
});
}
}